// cblist.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <list>
using namespace std;
#include "sigslot.h"

template<typename _Class>
class   NoLock
{
public:
    NoLock (_Class*)
    {
    };
    ~NoLock()
    {
    };
};

template<typename _Class>
class   Lock
{
private:
    _Class* _object;
public:
    Lock (_Class* object_)
        : _object(object_)
    {
        _object->lock();
    };
    ~Lock()
    {
        _object->unlock();
    };
};

template <typename _mutex_t = SIGSLOT_DEFAULT_MT_POLICY>
class   lockable
{
public:
    typedef typename _mutex_t _Mutex_t;
    typedef class Lock <lockable<_mutex_t> >  _Lock_t;
protected:
    _mutex_t    _mutex;
public:
    inline
    void    lock()
    {
        _mutex.lock();
    }

    inline
    void    unlock()
    {
        _mutex.unlock();
    }
};

template<typename LockableClass>
struct  locking_policy
{
    typedef NoLock<LockableClass> _Lock_t;
};

template<>
struct  locking_policy< lockable<sigslot::multi_threaded_local> >
{
    typedef lockable<sigslot::multi_threaded_local>::_Lock_t _Lock_t;
};

template<>
struct  locking_policy< lockable<sigslot::multi_threaded_global> >
{
    typedef lockable<sigslot::multi_threaded_global>::_Lock_t _Lock_t;
};

template<typename _return, typename  _class>
class INVOKER_BASE
{
public:
    typedef typename _class     _Handler_t;
    typedef typename _return    _Return_t;
};

template<typename _return, class  _class>
class NONVOID_INVOKER : public INVOKER_BASE<_return, _class>
{
public:

    static inline
        _Return_t   invoke(_Handler_t& object_, _Return_t (_Handler_t::*func_)())
    {
        return (object_.*func_)();
    }

    template <typename arg0>
    static inline
        _Return_t   invoke(_Handler_t& object_, _Return_t (_Handler_t::*func_)(arg0), arg0 _0)
    {
        return (object_.*func_)(_0);
    }

    template <typename arg0, typename arg1>
    static inline
        _Return_t   invoke(_Handler_t& object_, _Return_t (_Handler_t::*func_)(arg0, arg1), arg0 _0, arg1 _1)
    {
        return (object_.*func_)(_0, _1);
    }
};

template<typename _return, class  _class>
class   VOID_INVOKER : public INVOKER_BASE<_return, _class>
{
public:
    static inline
        void   invoke(_Handler_t& object_, _Return_t (_Handler_t::*func_)())
    {
        (object_.*func_)();
    }

    template <typename arg0>
    static inline
        void   invoke(_Handler_t& object_, _Return_t (_Handler_t::*func_)(arg0), arg0 _0)
    {
        (object_.*func_)(_0);
    }

    template <typename arg0, typename arg1>
    static inline
        void   invoke(_Handler_t& object_, _Return_t (_Handler_t::*func_)(arg0, arg1), arg0 _0, arg1 _1)
    {
        (object_.*func_)(_0, _1);
    }
};

//template <typename T> 
//struct is_void
//{
//    enum { value = false };
//};
//
//
//template <> 
//struct is_void<void>
//{
//    enum { value = true };
//};

template <typename _return, typename  _class, bool bVoid = _STD is_void<_return>::value >
class   INVOKER : public std::_If<bVoid, VOID_INVOKER<_return, _class>, NONVOID_INVOKER<_return, _class> >::type
{
public:
    typedef typename INVOKER_BASE<_return, _class>::_Handler_t   _Handler_t;
    typedef typename INVOKER_BASE<_return, _class>::_Return_t    _Return_t;
};

template<typename _return, typename  _class>
class event_prototype0 : public INVOKER<_return, _class>
{
public:
    enum {param_count = 0};
    typedef _Return_t (_Handler_t::*_Func_t)();
};

template<typename _return, typename  _class, typename arg0_type>
class event_prototype1 : public INVOKER<_return, _class>
{
public:
    enum {param_count = 1};
    typedef typename _Return_t (_Handler_t::*_Func_t)(arg0_type);
};


template <typename mt_policy>
class   event_handler;

template <typename mt_policy>
class   event_channel_base
{
public:
    typedef typename event_handler<mt_policy>   _Handler_base_t;
    typedef typename event_channel_base<mt_policy>   _Channel_base_t;
protected:
    _Handler_base_t* _object;
    void*            _method;    

protected:
    event_channel_base(const _Channel_base_t& other_)
        : _object(other_._object)
        , _method(other_._method)
    {}

    event_channel_base(_Handler_base_t* object_, void* method_)
        : _object(object_)
        , _method(method_)
    {}
public:

    inline
    _Handler_base_t*    handler_base()
    {
        return _object;
    }

    _Channel_base_t*    clone()
    {
        return new _Channel_base_t(*this);
    }

    _Channel_base_t*    duplicate(_Handler_base_t* handler_)
    {
        return new _Channel_base_t(handler_, _method);
    }

};

template<typename prototype>
class   event_channel : public event_channel_base<typename prototype::_Handler_t::_Policy_t>
{
public:
    typedef typename prototype              _Prototype_t;
    typedef typename prototype::_Handler_t  _Handler_t;
    typedef typename prototype::_Func_t     _Func_t;
    typedef event_channel<prototype>        _Channel_t;

    template <typename To, typename From>
    static inline To brute_cast(From from_)
    {
        union {
            To  _to;
            From _from;
        } u;
        u._from = from_;
        return u._to;
    }

public:
    event_channel(_Channel_t& other_)
        : event_channel_base(other_)
    {}

    event_channel(_Handler_t* object_, _Func_t method_)
        : event_channel_base(object_, *reinterpret_cast<void**>(&method_))
    {}


    inline
    _Handler_t*    object() const
    {
        return (_Handler_t*)_object;
    }

    inline
    _Func_t    method() const
    {
        return brute_cast<_Func_t, void*>(const_cast<void*>(_method));
    }

    inline
        void perform()
    {
        (object()->*method())();
    }

    template <typename arg0>
    inline
        void perform(arg0 _0)
    {
        (object()->*method())(_0);
    }

    template <typename arg0, typename arg1>
    inline
        void perform(arg0 _0, arg1 _1)
    {
        (object()->*method())(_0, _1);
    }

    template <typename arg0, typename arg1, typename arg2>
    inline
        void perform(arg0 _0, arg1 _1, arg2 _2)
    {
        (object()->*method())(_0, _1, _2);
    }
};

template<typename mt_policy>
class event_source_base : public mt_policy
{
public:
    typedef typename mt_policy  _Policy_t;
    typedef class event_handler<_Policy_t>      _Handler_base_t;
    typedef class event_channel_base<_Policy_t> _Channel_base_t;

    typedef std::list<_Channel_base_t*>  channels_list;

protected:
    channels_list   _channels;

    inline
        void    signal_connect(_Handler_base_t& handler_)
    {
        handler_.signal_connect(this);
    }

public:
    ~event_source_base()
    {
        disconnect_all();
    }

    void disconnect_all()
    {
        sigslot::lock_block<_Policy_t> lock(this);
        channels_list::iterator it = _channels.begin();
        channels_list::iterator itEnd = _channels.end();

        while(it != itEnd)
        {
            (*it)->handler_base()->signal_disconnect(this);
            delete *it++;
        }

        _channels.clear();
    }

    void release_handler(_Handler_base_t& handler_)
    {
        sigslot::lock_block<_Policy_t> lock(this);
        channels_list::iterator it = _channels.begin();
        channels_list::iterator itEnd = _channels.end();

        while(it != itEnd)
        {
            channels_list::iterator itNext = it;
            ++itNext;

            if((*it)->handler_base() == &handler_)
            {
                (*it)->handler_base()->signal_disconnect(this);
                delete *it;
                _channels.erase(it);
            }

            it = itNext;
        }
    }

    void copy_handler(const _Handler_base_t& from_, _Handler_base_t& to_)
    {
        sigslot::lock_block<_Policy_t> lock(this);
        channels_list::iterator it = _channels.begin();
        channels_list::iterator itEnd = _channels.end();

        while(it != itEnd)
        {
            if((*it)->handler_base() == &from_)
            {
                _channels.push_back((*it)->duplicate(&to_));
            }

            ++it;
        }
    }
};

template<typename _prototype>
class event_source : public event_source_base<typename _prototype::_Handler_t::_Policy_t>
{
public:
    typedef typename _prototype::_Handler_t _Handler_t;
    typedef typename _prototype::_Func_t    _Func_t;
    typedef typename _Handler_t::_Policy_t  _Policy_t;
    typedef event_channel<_prototype>       _Channel_t;
protected:

public:
    event_source()
    {
        ;
    }

    event_source(const event_source& s)
        : event_source_base(s)
    {
        ;
    }

    ~event_source()
    {
    }

    void connect(_Handler_t& handler_, _Func_t func_)
    {
        sigslot::lock_block<_Policy_t> lock(this);
        _Channel_t* channel = 
            new _Channel_t(&handler_, func_);
        _channels.push_back(channel);
        signal_connect(handler_);
    }

    void    emit()
    {
        sigslot::lock_block<_Policy_t> lock(this);
        channels_list::iterator itNext, it = _channels.begin();
        channels_list::iterator itEnd = _channels.end();

        while(it != itEnd)
        {
            itNext = it;
            ++itNext;

            ((_Channel_t*)(*it))->perform();

            it = itNext;
        }
    }

    inline
        void    operator()()
    {
        emit();
    }


    template<typename arg0_type>
    void    emit(arg0_type _0)
    {
        sigslot::lock_block<_Policy_t> lock(this);
        channels_list::iterator itNext, it = _channels.begin();
        channels_list::iterator itEnd = _channels.end();

        while(it != itEnd)
        {
            itNext = it;
            ++itNext;

            ((_Channel_t*)(*it))->perform(_0);

            it = itNext;
        }
    }

    template<typename arg0_type>
    inline
        void    operator()(arg0_type _0)
    {
        emit(_0);
    }


    template<typename arg0_type, typename arg1_type>
    void    emit(arg0_type _0, arg1_type _1)
    {
        sigslot::lock_block<_Policy_t> lock(this);
        channels_list::iterator itNext, it = _channels.begin();
        channels_list::iterator itEnd = _channels.end();

        while(it != itEnd)
        {
            itNext = it;
            ++itNext;

            ((_Channel_t*)(*it))->perform(_0);

            it = itNext;
        }
    }

    template<typename arg0_type, typename arg1_type>
    inline
        void    operator()(arg0_type _0, arg1_type _1)
    {
        emit(_0, _1);
    }

};

template<typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
class event_handler : public mt_policy 
{
public:

    typedef typename mt_policy                    _Policy_t;
    typedef class event_source_base<_Policy_t> _Source_t;
    friend  _Source_t;

private:

    typedef std::set<_Source_t*> source_set;
    typedef typename source_set::const_iterator const_iterator;

    source_set  _sources;

protected:
    void signal_connect(_Source_t* source_)
    {
        sigslot::lock_block<mt_policy> lock(this);
        _sources.insert(source_);
    }

    void signal_disconnect(_Source_t* source_)
    {
        sigslot::lock_block<mt_policy> lock(this);
        _sources.erase(source_);
    }


public:
    event_handler()
    {
        ;
    }

    event_handler(const event_handler& other_)
        : mt_policy(other_)
    {
        sigslot::lock_block<mt_policy> lock(this);
        const_iterator it = other_._sources.begin();
        const_iterator itEnd = other_._sources.end();

        while(it != itEnd)
        {
            (*it)->copy_handler(&other_, *this);
            _sources.insert(*it);
            ++it;
        }
    } 

    virtual ~event_handler()
    {
        disconnect_all();
    }

    void disconnect_all()
    {
        sigslot::lock_block<mt_policy> lock(this);
        const_iterator itNext, it = _sources.begin();
        const_iterator itEnd = _sources.end();

        while(it != itEnd)
        {
            itNext = it;
            ++itNext;
            (*it)->release_handler(*this);
            it = itNext;
        }

        _sources.clear();
    }

};

class   A : public event_handler<>
{
public:
    virtual int Func_A(int arg1) = 0;
    virtual void Func_V(void* arg1) = 0;
    //{
    //    return arg1/2;
    //}
};

class   B : public A
{
public:
    virtual int Func_A(int arg1)
    {
        return arg1*2;
    }

    virtual void Func_V(void* arg1)
    {
        arg1;
        return;
    }
};


class   Receiver : public event_handler<>
{
public:
    void    OnEvent()
    {
        // 
    }

    void    OnEvent2()
    {
        // 
    }

    int    OnEvent3(int arg)
    {
        return arg*2;
    }
};

class   NL 
{
};

class   L : public lockable<>
{
public:
};

int _tmain(int argc, _TCHAR* argv[])
{
    //NL nl;
    //L l;
    //locking_policy<NL>::_Lock_t no_lock(&nl);
    //L::_Lock_t lock(&l);
    typedef event_prototype1<int, A, int> vfunc;
    B b;
    event_channel<vfunc> evc(&b, &A::Func_A);

    evc.perform(10);

    vfunc::invoke(b, &A::Func_A, 100);

    typedef event_prototype0<void, Receiver> rfunc;
    typedef event_prototype1<int, Receiver, int> rfunc2;

    Receiver rcv;
    Receiver rcv2;

    event_source<rfunc>   signal;
    {
        event_source<rfunc2>   signal_int;

        signal.connect(rcv, &Receiver::OnEvent);
        signal.connect(rcv2, &Receiver::OnEvent2);
        signal_int.connect(rcv, &Receiver::OnEvent3);
        signal();
        signal_int(10);
        rcv2.disconnect_all();
        signal();
        signal_int(100);
        signal.release_handler(rcv);
        signal_int(50);
    }
    signal();
}

#if 0

class Switch    // aka Event_Sender
{
public:
    signal0<> Clicked;
};

class Light : public has_slots<> // aka Event_Handler
{
public:
    void ToggleState();
    void TurnOn();
    void TurnOff();
};

Switch sw3, sw4, all_on, all_off;
Light lp3, lp4;

sw3.Clicked.connect(&lp3, &Light::ToggleState);
sw4.Clicked.connect(&lp4, &Light::ToggleState);

all_on.Clicked.connect(&lp1, &Light::TurnOn());
all_on.Clicked.connect(&lp2, &Light::TurnOn());
all_on.Clicked.connect(&lp3, &Light::TurnOn());
all_on.Clicked.connect(&lp4, &Light::TurnOn());
all_off.Clicked.connect(&lp1, &Light::TurnOff());
all_off.Clicked.connect(&lp2, &Light::TurnOff());
all_off.Clicked.connect(&lp3, &Light::TurnOff());
all_off.Clicked.connect(&lp4, &Light::TurnOff());

#endif